
package com.huawei.demo;

import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ClientRequestException;
import com.huaweicloud.sdk.core.exception.ServerResponseException;
import com.huaweicloud.sdk.core.http.HttpConfig;
import com.huaweicloud.sdk.drs.v3.DrsClient;
import com.huaweicloud.sdk.drs.v3.model.BatchCheckJobsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchCheckJobsResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchCheckResultsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchCheckResultsResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchCreateJobReq;
import com.huaweicloud.sdk.drs.v3.model.BatchCreateJobsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchCreateJobsResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchListJobStatusRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchListJobStatusResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchModifyJobReq;
import com.huaweicloud.sdk.drs.v3.model.BatchPrecheckReq;
import com.huaweicloud.sdk.drs.v3.model.BatchQueryJobReqPage;
import com.huaweicloud.sdk.drs.v3.model.BatchQueryParamReq;
import com.huaweicloud.sdk.drs.v3.model.BatchQueryPrecheckResultReq;
import com.huaweicloud.sdk.drs.v3.model.BatchSetObjectsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchSetObjectsResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchShowParamsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchShowParamsResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchStartJobReq;
import com.huaweicloud.sdk.drs.v3.model.BatchStartJobsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchTestConnectionReq;
import com.huaweicloud.sdk.drs.v3.model.BatchUpdateDatabaseObjectReq;
import com.huaweicloud.sdk.drs.v3.model.BatchUpdateJobRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchUpdateJobResponse;
import com.huaweicloud.sdk.drs.v3.model.BatchValidateConnectionsRequest;
import com.huaweicloud.sdk.drs.v3.model.BatchValidateConnectionsResponse;
import com.huaweicloud.sdk.drs.v3.model.CheckJobResp;
import com.huaweicloud.sdk.drs.v3.model.CreateJobReq;
import com.huaweicloud.sdk.drs.v3.model.CreateJobResp;
import com.huaweicloud.sdk.drs.v3.model.Endpoint;
import com.huaweicloud.sdk.drs.v3.model.ModifyJobReq;
import com.huaweicloud.sdk.drs.v3.model.PreCheckInfo;
import com.huaweicloud.sdk.drs.v3.model.QueryJobsReq;
import com.huaweicloud.sdk.drs.v3.model.QueryPreCheckResp;
import com.huaweicloud.sdk.drs.v3.model.StartInfo;
import com.huaweicloud.sdk.drs.v3.model.TestEndPoint;
import com.huaweicloud.sdk.drs.v3.model.UpdateDatabaseObjectReq;
import com.huaweicloud.sdk.drs.v3.region.DrsRegion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class BatchCreateJobsDemo {
    private static final Logger logger = LoggerFactory.getLogger(BatchCreateJobsDemo.class.getName());

    public static void main(String[] args) {
        // 创建认证
        String ak = "<YOUR AK>";
        String sk = "<YOUR SK>";

        ICredential auth = new BasicCredentials().withAk(ak).withSk(sk);
        // 配置客户端属性
        HttpConfig config = HttpConfig.getDefaultHttpConfig();
        config.withIgnoreSSLVerification(true);

        // 创建DrsClient实例
        DrsClient client = DrsClient.newBuilder().withCredential(auth).withHttpConfig(config)
                .withRegion(DrsRegion.CN_NORTH_4).build();
        BatchCreateJobsRequest request = getBatchCreateJobsRequest();
        try {
            BatchCreateJobsResponse response = client.batchCreateJobs(request);
            if (response.getHttpStatusCode() == 202) {
                List<CreateJobResp> results = response.getResults();
                CreateJobResp createJobResp = results.get(0);
                String status = createJobResp.getStatus();
                // 任务状态为配置中才能进行下一步操作
                while (!QueryJobsReq.StatusEnum.CONFIGURATION.getValue().equals(status)) {
                    TimeUnit.SECONDS.sleep(20);
                    BatchListJobStatusRequest batchListProgressesRequest = new BatchListJobStatusRequest();
                    BatchQueryJobReqPage batchQueryJobReqPage = new BatchQueryJobReqPage();
                    List<String> jobs = new ArrayList<>();
                    jobs.add(createJobResp.getId());
                    batchQueryJobReqPage.withJobs(jobs);
                    batchListProgressesRequest.setBody(batchQueryJobReqPage);
                    BatchListJobStatusResponse batchListJobStatusResponse = client.batchListJobStatus(batchListProgressesRequest);
                    status = batchListJobStatusResponse.getResults().get(0).getStatus().getValue();
                }
                // 测试连接失败返回
                if (connectionFail(client, createJobResp)) {
                    return;
                }
                // 源库，目标库都连接成功，更新任务信息
                BatchUpdateJobRequest batchUpdateJobRequest = getBatchUpdateJobRequest(createJobResp);
                BatchUpdateJobResponse batchUpdateJobResponse = client.batchUpdateJob(batchUpdateJobRequest);
                if (batchUpdateJobResponse.getHttpStatusCode() != 200) {
                    logger.error(batchUpdateJobResponse.getResults().toString());
                    return;
                }
                // 更新任务成功后，设置同步对象
                BatchSetObjectsResponse batchSetObjectsResponse = getBatchSetObjectsResponse(client, createJobResp);
                if (batchSetObjectsResponse.getHttpStatusCode() != 202) {
                    logger.error(batchSetObjectsResponse.getResults().toString());
                    return;
                }
                // 预检查
                if (precheckFail(client, createJobResp)) {
                    return;
                }
                // 查询预检查结果
                String totalPassedRate = getTotalPassedRate(client, createJobResp);
                // 通过率为100%时启动任务
                startJob(client, createJobResp, totalPassedRate);
            }
            logger.error(response.toString());
        } catch (ClientRequestException e) {
            logger.error(e.getMessage());
        } catch (ServerResponseException e) {
            logger.error(e.getMessage());
        } catch (InterruptedException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 测试连接
     * @param client
     * @param createJobResp
     * @return
     */
    private static boolean connectionFail(DrsClient client, CreateJobResp createJobResp) {
        BatchValidateConnectionsRequest batchValidateConnectionsRequest = getBatchValidateConnectionsRequest(createJobResp);
        BatchValidateConnectionsResponse batchValidateConnectionsResponse = client.batchValidateConnections(batchValidateConnectionsRequest);
        int httpStatusCode = batchValidateConnectionsResponse.getHttpStatusCode();
        if (httpStatusCode != 200) {
            logger.error(batchValidateConnectionsResponse.getResults().toString());
            return true;
        }

        List<CheckJobResp> responseResults = batchValidateConnectionsResponse.getResults();
        if (!responseResults.get(0).getSuccess() || !responseResults.get(1).getSuccess()) {
            logger.error(responseResults.toString());
            return true;
        }
        return false;
    }

    /**
     * 获取数据库参数
     * @param client
     * @param createJobResp
     * @return
     */
    private static boolean getParamFail(DrsClient client, CreateJobResp createJobResp) {
        BatchShowParamsRequest batchShowParamsRequest = new BatchShowParamsRequest();
        BatchQueryParamReq batchQueryParamReq = new BatchQueryParamReq();
        batchQueryParamReq.withRefresh("1");
        List<String> jobs = new ArrayList<>();
        jobs.add(createJobResp.getId());
        batchQueryParamReq.withJobs(jobs);
        batchShowParamsRequest.withBody(batchQueryParamReq);
        BatchShowParamsResponse batchShowParamsResponse = client.batchShowParams(batchShowParamsRequest);
        if (batchShowParamsResponse.getHttpStatusCode() != 202) {
            logger.error(batchShowParamsResponse.getParamsList().toString());
            return true;
        }
        return false;
    }

    /**
     * 获取预检查结果
     * @param client
     * @param createJobResp
     * @return
     * @throws InterruptedException
     */
    private static String getTotalPassedRate(DrsClient client, CreateJobResp createJobResp) throws InterruptedException {
        BatchCheckResultsRequest batchCheckResultsRequest = new BatchCheckResultsRequest();
        BatchQueryPrecheckResultReq batchQueryPrecheckResultReq = new BatchQueryPrecheckResultReq();
        List<String> jobIds = new ArrayList<>();
        jobIds.add(createJobResp.getId());
        batchQueryPrecheckResultReq.withJobs(jobIds);
        batchCheckResultsRequest.withBody(batchQueryPrecheckResultReq);
        BatchCheckResultsResponse batchCheckResultsResponse = client.batchCheckResults(batchCheckResultsRequest);
        QueryPreCheckResp queryPreCheckResp = batchCheckResultsResponse.getResults().get(0);
        String progress = queryPreCheckResp.getProcess();
        String totalPassedRate = queryPreCheckResp.getTotalPassedRate();
        while (!progress.equals("100%")) {
            TimeUnit.SECONDS.sleep(20);
            BatchCheckResultsResponse checkResultsResponse = client.batchCheckResults(batchCheckResultsRequest);
            logger.info(checkResultsResponse.getResults().toString());
            progress = checkResultsResponse.getResults().get(0).getProcess();
            totalPassedRate = checkResultsResponse.getResults().get(0).getTotalPassedRate();
        }
        return totalPassedRate;
    }

    /**
     * 启动任务
     * @param client
     * @param createJobResp
     * @param totalPassedRate
     */
    private static void startJob(DrsClient client, CreateJobResp createJobResp, String totalPassedRate) {
        if (totalPassedRate.equals("100%")) {
            // 获取数据库参数，如果需要修改参数调修改数据库参数接口修改
            if (getParamFail(client, createJobResp)) {
                return;
            }
            BatchStartJobsRequest batchStartJobsRequest = new BatchStartJobsRequest();
            BatchStartJobReq batchStartJobReq = new BatchStartJobReq();
            List<StartInfo> startInfos = new ArrayList<>();
            startInfos.add(new StartInfo().withJobId(createJobResp.getId()));
            batchStartJobReq.withJobs(startInfos);
            batchStartJobsRequest.withBody(batchStartJobReq);
            client.batchStartJobs(batchStartJobsRequest);
        }
    }

    /**
     * 启动预检查
     * @param client
     * @param createJobResp
     * @return
     */
    private static boolean precheckFail(DrsClient client, CreateJobResp createJobResp) {
        BatchCheckJobsRequest batchCheckJobsRequest = new BatchCheckJobsRequest();
        BatchPrecheckReq batchPrecheckReq = new BatchPrecheckReq();
        List<PreCheckInfo> preCheckInfos = new ArrayList<>();
        PreCheckInfo preCheckInfo = new PreCheckInfo();
        preCheckInfo.withJobId(createJobResp.getId());
        preCheckInfo.withPrecheckMode(PreCheckInfo.PrecheckModeEnum.FORSTARTJOB);
        preCheckInfos.add(preCheckInfo);
        batchPrecheckReq.withJobs(preCheckInfos);
        batchCheckJobsRequest.withBody(batchPrecheckReq);
        BatchCheckJobsResponse batchCheckJobsResponse = client.batchCheckJobs(batchCheckJobsRequest);
        if (batchCheckJobsResponse.getHttpStatusCode() != 200) {
            logger.error(batchCheckJobsResponse.getResults().toString());
            return true;
        }
        return false;
    }

    /**
     * 设置迁移对象
     * @param client
     * @param createJobResp
     * @return
     */
    private static BatchSetObjectsResponse getBatchSetObjectsResponse(DrsClient client, CreateJobResp createJobResp) {
        BatchSetObjectsRequest batchSetObjectsRequest = new BatchSetObjectsRequest();
        BatchUpdateDatabaseObjectReq batchUpdateDatabaseObjectReq = new BatchUpdateDatabaseObjectReq();
        List<UpdateDatabaseObjectReq> jobs = new ArrayList<>();
        UpdateDatabaseObjectReq updateDatabaseObjectReq = new UpdateDatabaseObjectReq();
        updateDatabaseObjectReq.withJobId(createJobResp.getId());
        updateDatabaseObjectReq.withSelected(false);
        updateDatabaseObjectReq.withJob(new ArrayList<>());
        jobs.add(updateDatabaseObjectReq);
        batchUpdateDatabaseObjectReq.withJobs(jobs);
        batchSetObjectsRequest.withBody(batchUpdateDatabaseObjectReq);
        return client.batchSetObjects(batchSetObjectsRequest);
    }

    /**
     * 构建修改任务请求体
     * @param createJobResp
     * @return
     */
    private static BatchUpdateJobRequest getBatchUpdateJobRequest(CreateJobResp createJobResp) {
        BatchUpdateJobRequest batchUpdateJobRequest = new BatchUpdateJobRequest();
        BatchModifyJobReq batchModifyJobReq = new BatchModifyJobReq();
        List<ModifyJobReq> jobs = new ArrayList<>();
        ModifyJobReq modifyJobReq = new ModifyJobReq();
        modifyJobReq.withJobId(createJobResp.getId());
        modifyJobReq.withName("<YOUR TASK NAME>");
        Endpoint sourceEndpoint = new Endpoint();
        sourceEndpoint.withRegion("<YOUR Region>");
        sourceEndpoint.withIp("<YOUR Ip>");
        sourceEndpoint.withDbPort(3306);
        sourceEndpoint.withDbUser("<YOUR DbUser>");
        sourceEndpoint.withDbPassword("<YOUR DbPassword>");
        sourceEndpoint.setSslLink(false);
        sourceEndpoint.withDbType(Endpoint.DbTypeEnum.MYSQL);
        sourceEndpoint.withProjectId("<YOUR ProjectId>");
        Endpoint targetEndpoint = new Endpoint();
        targetEndpoint.withRegion("<YOUR Region>");
        targetEndpoint.withDbType(Endpoint.DbTypeEnum.MYSQL);
        targetEndpoint.withDbUser("<YOUR DbUser>");
        targetEndpoint.withDbPassword("<YOUR DbPassword>");
        targetEndpoint.withProjectId("<YOUR ProjectId>");
        targetEndpoint.withInstId("<YOUR InstId>");

        modifyJobReq.withSourceEndpoint(sourceEndpoint);
        modifyJobReq.withTargetEndpoint(targetEndpoint);
        modifyJobReq.withNodeType(ModifyJobReq.NodeTypeEnum.HIGH);
        modifyJobReq.withEngineType(ModifyJobReq.EngineTypeEnum.MYSQL);
        modifyJobReq.withNetType(ModifyJobReq.NetTypeEnum.EIP);
        modifyJobReq.withStoreDbInfo(true);
        jobs.add(modifyJobReq);
        batchModifyJobReq.withJobs(jobs);
        batchUpdateJobRequest.withBody(batchModifyJobReq);
        return batchUpdateJobRequest;
    }

    /**
     * 构建测试连接请求体
     * @param createJobResp
     * @return
     */
    private static BatchValidateConnectionsRequest getBatchValidateConnectionsRequest(CreateJobResp createJobResp) {
        BatchValidateConnectionsRequest batchValidateConnectionsRequest = new BatchValidateConnectionsRequest();
        List<TestEndPoint> jobs = new ArrayList<>();
        // 源库信息
        TestEndPoint so = new TestEndPoint();
        so.withId(createJobResp.getId());
        so.withIp("<YOUR Ip>");
        so.withNetType(TestEndPoint.NetTypeEnum.EIP);
        so.withDbPort(3306);
        so.withDbUser("<YOUR DbUser>");
        so.withDbPassword("<YOUR DbPassword>");
        so.withProjectId("<YOUR ProjectId>");
        so.withRegion("<YOUR Region>");
        so.withDbType(TestEndPoint.DbTypeEnum.MYSQL);
        so.withEndPointType(TestEndPoint.EndPointTypeEnum.SO);
        // 目标库信息
        TestEndPoint ta = new TestEndPoint();
        ta.withId(createJobResp.getId());
        ta.withInstId("<YOUR InstId>");
        ta.withIp("<YOUR Ip>");
        ta.withNetType(TestEndPoint.NetTypeEnum.EIP);
        ta.withDbPort(3306);
        ta.withDbPassword("<YOUR DbPassword>");
        ta.withProjectId("<YOUR ProjectId>");
        ta.withRegion("<YOUR Region>");
        ta.withEndPointType(TestEndPoint.EndPointTypeEnum.TA);
        ta.withDbType(TestEndPoint.DbTypeEnum.MYSQL);
        ta.withDbUser("<YOUR DbUser>");
        jobs.add(so);
        jobs.add(ta);
        BatchTestConnectionReq batchTestConnectionReq = new BatchTestConnectionReq();
        batchTestConnectionReq.withJobs(jobs);
        batchValidateConnectionsRequest.setBody(batchTestConnectionReq);
        return batchValidateConnectionsRequest;
    }

    /**
     * 构建创建任务请求体
     * @return
     */
    private static BatchCreateJobsRequest getBatchCreateJobsRequest() {
        BatchCreateJobsRequest request = new BatchCreateJobsRequest();
        BatchCreateJobReq body = new BatchCreateJobReq();
        List<CreateJobReq> jobs = new ArrayList<>();
        CreateJobReq createJobReq = new CreateJobReq();
        createJobReq.withName("<YOUR TASK NAME>");
        createJobReq.withEngineType(CreateJobReq.EngineTypeEnum.MYSQL);
        createJobReq.withNetType(CreateJobReq.NetTypeEnum.EIP);
        createJobReq.withNodeType(CreateJobReq.NodeTypeEnum.HIGH);
        createJobReq.withJobDirection(CreateJobReq.JobDirectionEnum.UP);
        createJobReq.withBindEip(true);
        createJobReq.withDbUseType(CreateJobReq.DbUseTypeEnum.MIGRATION);
        createJobReq.withTaskType(CreateJobReq.TaskTypeEnum.FULL_INCR_TRANS);
        createJobReq.withCustomizeSutnetId("<YOUR CustomizeSutnetId>");
        createJobReq.withExpiredDays("14");
        Endpoint sourceEndpoint = new Endpoint();
        sourceEndpoint.withDbType(Endpoint.DbTypeEnum.MYSQL);
        createJobReq.withSourceEndpoint(sourceEndpoint);
        Endpoint targetEndpoint = new Endpoint();
        targetEndpoint.withRegion("<YOUR region>");
        targetEndpoint.withDbType(Endpoint.DbTypeEnum.MYSQL);
        targetEndpoint.withInstId("<YOUR InstId>");
        targetEndpoint.withProjectId("<YOUR ProjectId>");
        createJobReq.withIsTargetReadonly(true);
        createJobReq.withTargetEndpoint(targetEndpoint);
        jobs.add(createJobReq);
        body.withJobs(jobs);
        request.withBody(body);
        return request;
    }
}